using Firestarter.Test.Base;
using FireStarterModeller.BO;
using FireStarterModeller.Test.BO;
using FireStarterModeller.UI.DetailsView;
using NUnit.Framework;

namespace FireStarterModeller.Test.UI.DetailsView.Model
{
    [TestFixture]
    public class TestSolutionViewModel 
    {
        [TestFixtureSetUp]
        public void SetupFixture()
        {
            TestUtilsDomain.SetupFixture();
        }
        [SetUp]
        public void SetupTest()
        {
            TestUtilsDomain.SetupTest();
        }

        #region Building model from DMSolution

        //Display solution with one assembly 
        [Test]
        public void Test_EmptySolution()
        {
            //---------------Set up test pack-------------------
            DMSolution solution = TestUtilsShared.CreateSavedDMSolution();
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            SolutionViewModel model = SolutionViewModel.BuildFrom(solution);
            //---------------Test Result -----------------------
            Assert.AreSame(solution.SolutionName, model.Name);
            Assert.AreEqual(1, model.Assemblies.Count);
            Assert.AreEqual(solution.DefaultAssembly.Name, model.Assemblies[0].Name);
        }

        //Display solution with one assembly 
        [Test]
        public void Test_BuildWithClasses()
        {
            //---------------Set up test pack-------------------
            DMSolution solution = TestUtilsShared.CreateSavedDMSolution();
            DMClass dmClass1 = solution.DefaultAssembly.Classes.CreateBusinessObject();
            solution.DefaultAssembly.Classes.CreateBusinessObject();

            //---------------Execute Test ----------------------
            SolutionViewModel model = SolutionViewModel.BuildFrom(solution);
            //---------------Test Result -----------------------
            Assert.AreEqual(1, model.Assemblies.Count);
            Assert.AreEqual(2, model.Assemblies[0].Classes.Count);
            Assert.AreEqual(dmClass1.ClassNameBO, model.Assemblies[0].Classes[0].Name);
        }

        //Create assembly
        [Test]
        public void Test_AddingAssembly_UpdatesModel()
        {
            //---------------Set up test pack-------------------
            DMSolution solution = TestUtilsShared.CreateSavedDMSolution();
            SolutionViewModel model = SolutionViewModel.BuildFrom(solution);
            const string assemblyName = "Assembly2";
            //---------------Assert PreConditions---------------            
            Assert.AreEqual(1, model.Assemblies.Count);
            //---------------Execute Test ----------------------
            solution.CreateAssembly(assemblyName);
            //---------------Test Result -----------------------
            Assert.AreEqual(2, model.Assemblies.Count);
            Assert.AreEqual(assemblyName, model.Assemblies[1].Name);
            //---------------Tear Down -------------------------          
        }

        //Create assembly
        //Delete assembly
        [Test]
        public void Test_RemovingAssembly_UpdatesModel()
        {
            //---------------Set up test pack-------------------
            DMSolution solution = TestUtilsShared.CreateSavedDMSolution();
            SolutionViewModel model = SolutionViewModel.BuildFrom(solution);
            //---------------Assert PreConditions---------------      
            Assert.AreEqual(1, model.Assemblies.Count);
            //---------------Execute Test ----------------------
            solution.Assemblies.Remove(solution.DefaultAssembly);
            //---------------Test Result -----------------------
            Assert.AreEqual(0, model.Assemblies.Count);
            //---------------Tear Down -------------------------          
        }

        //Create class (using current assembly)
        [Test]
        public void Test_AddingClass_UpdatesModel()
        {
            //---------------Set up test pack-------------------
            DMSolution solution = TestUtilsShared.CreateSavedDMSolution();
            DMAssembly assembly = solution.DefaultAssembly;

            string className = TestUtilsShared.GetRandomString();
            SolutionViewModel model = SolutionViewModel.BuildFrom(solution);
            //---------------Assert Precondition----------------
            Assert.AreEqual(0, assembly.Classes.Count);
            Assert.AreEqual(0, model.Assemblies[0].Classes.Count);
            //---------------Execute Test ----------------------
            assembly.CreateClass(className);
            //---------------Test Result -----------------------
            Assert.AreEqual(1, assembly.Classes.Count);
            Assert.AreEqual(1, model.Assemblies[0].Classes.Count);
            Assert.AreEqual(className, model.Assemblies[0].Classes[0].Name);
        }

        //Create class (using current assembly)
        //delete class
        [Test]
        public void Test_RemovingClass_UpdatesModel()
        {
            //---------------Set up test pack-------------------
            DMSolution solution = TestUtilsShared.CreateSavedDMSolution();
            DMAssembly assembly = solution.DefaultAssembly;
            const string className = "Class1";
            DMClass dmClass = assembly.CreateClass(className);
            SolutionViewModel model = SolutionViewModel.BuildFrom(solution);
            //---------------Assert Precondition----------------
            Assert.AreEqual(1, model.Assemblies[0].Classes.Count);
            //---------------Execute Test ----------------------
            assembly.Classes.Remove(dmClass);
            //---------------Test Result -----------------------
            Assert.AreEqual(0, model.Assemblies[0].Classes.Count);
        }

        //Rename assembly
        [Test]
        public void Test_RenamingAssembly_UpdatesModel()
        {
            //---------------Set up test pack-------------------
            DMSolution solution = TestUtilsShared.CreateSavedDMSolution();
            DMAssembly assembly = solution.DefaultAssembly;
            assembly.Name = "OldAssemblyName";
            SolutionViewModel model = SolutionViewModel.BuildFrom(solution);
            const string newAssemblyName = "NewAssemblyName";

            //---------------Execute Test ----------------------
            assembly.Name = newAssemblyName;
            //---------------Test Result -----------------------
            Assert.AreEqual(newAssemblyName, model.Assemblies[0].Name);
            //---------------Tear Down -------------------------          
        }

        [Test]
        public void Test_UpdatingClassName_UpdatesModel()
        {
            //---------------Set up test pack-------------------
            DMSolution solution = TestUtilsShared.CreateSavedDMSolution();
            DMClass dmClass = solution.DefaultAssembly.CreateClass("OldClassName");
            SolutionViewModel model = SolutionViewModel.BuildFrom(solution);
            const string newClassName = "NewClassName";

            //---------------Execute Test ----------------------
            dmClass.ClassNameBO = newClassName;
            //---------------Test Result -----------------------
            Assert.AreEqual(newClassName, model.Assemblies[0].Classes[0].Name);
            //---------------Tear Down -------------------------          
        } 
        #endregion
    
        //Select assembly
        [Test]
        public void Test_CurrentAssembly()
        {
            //---------------Set up test pack-------------------
            SolutionViewModel model = CreateSolutionViewModel();
            AddAssemblyToModel(model, "Assembly1");
            SolutionViewModel.AssemblyModel assemblyModel = AddAssemblyToModel(model, "Assembly2");

            //---------------Execute Test ----------------------
            model.CurrentAssembly = assemblyModel;

            //---------------Test Result -----------------------
            Assert.AreEqual(assemblyModel, model.CurrentAssembly);

            //---------------Tear Down -------------------------          
        }

        //Select assembly
        [Test]
        public void Test_CurrentAssembly_Default()
        {
            //---------------Set up test pack-------------------
            SolutionViewModel model = CreateSolutionViewModel();
            SolutionViewModel.AssemblyModel assemblyModel = AddAssemblyToModel(model, "Assembly1");
            AddAssemblyToModel(model, "Assembly2");
            
            //---------------Execute Test ----------------------
            SolutionViewModel.AssemblyModel currentAssemblyModel = model.CurrentAssembly;

            //---------------Test Result -----------------------
            Assert.AreSame(currentAssemblyModel, assemblyModel);

            //---------------Tear Down -------------------------          
        }
        
        //Select assembly
        [Test]
        public void Test_CurrentAssemblyChangedEvent()
        {
            //---------------Set up test pack-------------------
            SolutionViewModel model = CreateSolutionViewModel();
            SolutionViewModel.AssemblyModel assemblyModel1 = AddAssemblyToModel(model, "Assembly1");
            SolutionViewModel.AssemblyModel assemblyModel2 = AddAssemblyToModel(model, "Assembly2");
            SolutionViewModel.AssemblyModel currentAssembly = assemblyModel1;
            model.CurrentAssemblyChanged += assemblyModel => currentAssembly = assemblyModel;

            //---------------Assert PreConditions---------------            
            Assert.AreSame(currentAssembly, model.CurrentAssembly);

            //---------------Execute Test ----------------------
            model.CurrentAssembly = assemblyModel2;

            //---------------Test Result -----------------------
            Assert.AreSame(assemblyModel2, model.CurrentAssembly);
            Assert.AreSame(currentAssembly, assemblyModel2);
            //---------------Tear Down -------------------------          
        }
        
        //Create assembly
        [Test]
        public void Test_AssemblyAddedEvent()
        {
            //---------------Set up test pack-------------------
            SolutionViewModel model = CreateSolutionViewModel();
            SolutionViewModel.AssemblyModel assemblyModel1 = new SolutionViewModel.AssemblyModel("Assembly1");
            SolutionViewModel.AssemblyModel eventAssemblyModel = null;
            model.AssemblyAdded += assemblyModel => eventAssemblyModel = assemblyModel;

            //---------------Execute Test ----------------------
            model.Assemblies.Add(assemblyModel1);

            //---------------Test Result -----------------------
            Assert.AreSame(assemblyModel1, eventAssemblyModel);
        }

        //Create assembly
        //Delete assembly
        [Test]
        public void Test_AssemblyRemovedEvent()
        {
            //---------------Set up test pack-------------------
            SolutionViewModel model = CreateSolutionViewModel();
            SolutionViewModel.AssemblyModel assemblyModel1 = AddAssemblyToModel(model, "Assembly1");
            SolutionViewModel.AssemblyModel eventAssemblyModel = null;
            model.AssemblyRemoved += assemblyModel => eventAssemblyModel = assemblyModel;

            //---------------Execute Test ----------------------
            bool removed = model.Assemblies.Remove(assemblyModel1);

            //---------------Test Result -----------------------
            Assert.IsTrue(removed);
            Assert.AreSame(assemblyModel1, eventAssemblyModel);
        }

        //Rename assembly
        [Test]
        public void Test_AssemblyRenamedEvent()
        {
            //---------------Set up test pack-------------------
            SolutionViewModel model = CreateSolutionViewModel();
            SolutionViewModel.AssemblyModel assemblyModel1 = AddAssemblyToModel(model, "Assembly1");

            string propertyName = "";
            assemblyModel1.PropertyChanged += (sender, e) => propertyName = e.PropertyName;

            //---------------Execute Test ----------------------
            assemblyModel1.Name = "NewName";

            //---------------Test Result -----------------------
            Assert.AreEqual("Name", propertyName);
        }


        //Select class
        [Test]
        public void Test_CurrentClass_Default()
        {
            //---------------Set up test pack-------------------
            SolutionViewModel model = CreateSolutionViewModel();
            SolutionViewModel.AssemblyModel assemblyModel = AddAssemblyToModel(model, "Assembly1");
            AddClassToModel(assemblyModel, "Class1");

            //---------------Execute Test ----------------------
            SolutionViewModel.ClassModel currentClassModel = assemblyModel.CurrentClass;
            //---------------Test Result -----------------------

            Assert.IsNull(currentClassModel);
            //---------------Tear Down -------------------------          
        }

        //Select class
        [Test]
        public void Test_CurrentClass_Set()
        {
            //---------------Set up test pack-------------------
            SolutionViewModel model = CreateSolutionViewModel();
            SolutionViewModel.AssemblyModel assemblyModel = AddAssemblyToModel(model, "Assembly1");
            SolutionViewModel.ClassModel classModel = AddClassToModel(assemblyModel, "Class1");

            //---------------Execute Test ----------------------
            assemblyModel.CurrentClass = classModel;
            //---------------Test Result -----------------------

            Assert.AreSame(classModel, assemblyModel.CurrentClass);
            //---------------Tear Down -------------------------          
        }

        //Select class
        [Test]
        public void Test_CurrentClassChangedEvent()
        {
            //---------------Set up test pack-------------------
            SolutionViewModel model = CreateSolutionViewModel();
            SolutionViewModel.AssemblyModel assemblyModel = AddAssemblyToModel(model, "Assembly1");
            SolutionViewModel.ClassModel classModel = AddClassToModel(assemblyModel, "Class1");
            SolutionViewModel.ClassModel eventClassModel = null;
            assemblyModel.CurrentClassChanged += model1 => eventClassModel = model1;
            //---------------Execute Test ----------------------
            assemblyModel.CurrentClass = classModel;
            //---------------Test Result -----------------------

            Assert.AreSame(classModel, eventClassModel);
            Assert.AreSame(eventClassModel, assemblyModel.CurrentClass);
            //---------------Tear Down -------------------------          
        }



        //Create class (using current assembly)
        [Test]
        public void Test_ClassAddedEvent()
        {
            //---------------Set up test pack-------------------
            SolutionViewModel model = CreateSolutionViewModel();
            SolutionViewModel.AssemblyModel assemblyModel = AddAssemblyToModel(model, "Assembly1");
            string className = TestUtilsShared.GetRandomString();
            SolutionViewModel.ClassModel classModel = new SolutionViewModel.ClassModel(className);
            SolutionViewModel.ClassModel eventClassModel = null;
            assemblyModel.ClassAdded += classModel1 => eventClassModel = classModel1;
            //---------------Assert PreConditions---------------            

            //---------------Execute Test ----------------------
            assemblyModel.Classes.Add(classModel);
            //---------------Test Result -----------------------

            Assert.AreSame(classModel, eventClassModel);
            //---------------Tear Down -------------------------          
        }

        //Create class (using current assembly)
        //delete class
        [Test]
        public void Test_ClassRemovedEvent()
        {
            //---------------Set up test pack-------------------
            SolutionViewModel model = CreateSolutionViewModel();
            SolutionViewModel.AssemblyModel assemblyModel = AddAssemblyToModel(model, "Assembly1");
            SolutionViewModel.ClassModel classModel = AddClassToModel(assemblyModel, "Class1");

            SolutionViewModel.ClassModel eventClassModel = null;
            assemblyModel.ClassRemoved += classModel1 => eventClassModel = classModel1;
            //---------------Assert PreConditions---------------            

            //---------------Execute Test ----------------------
            assemblyModel.Classes.Remove(classModel);
            //---------------Test Result -----------------------

            Assert.AreSame(classModel, eventClassModel);
            //---------------Tear Down -------------------------          
        }


        //Rename class
        [Test]
        public void Test_ClassRenamedEvent()
        {
            //---------------Set up test pack-------------------
            SolutionViewModel model = CreateSolutionViewModel();
            SolutionViewModel.AssemblyModel assemblyModel1 = AddAssemblyToModel(model, "Assembly1");
            SolutionViewModel.ClassModel classModel = AddClassToModel(assemblyModel1, "Class1");

            string propertyName = "";
            classModel.PropertyChanged += (sender, e) => propertyName = e.PropertyName;

            //---------------Execute Test ----------------------
            classModel.Name = "NewName";

            //---------------Test Result -----------------------
            Assert.AreEqual("Name", propertyName);
        }


        private static SolutionViewModel.ClassModel AddClassToModel(SolutionViewModel.AssemblyModel assemblyModel, string className) {
            SolutionViewModel.ClassModel classModel = new SolutionViewModel.ClassModel(className);
            assemblyModel.Classes.Add(classModel);
            return classModel;
        }


        private static SolutionViewModel.AssemblyModel AddAssemblyToModel(SolutionViewModel model, string assemblyName)
        {
            SolutionViewModel.AssemblyModel assemblyModel1 = new SolutionViewModel.AssemblyModel(assemblyName);
            model.Assemblies.Add(assemblyModel1);
            return assemblyModel1;
        }

        private static SolutionViewModel CreateSolutionViewModel() { return new SolutionViewModel("Project1"); }

    }
}